import socket
import os
import time


def is_path_a_file(path):
    """
    判断给定的路径是否指向一个文件

    参数:
    path (str): 要检查的路径

    返回:
    bool: 如果路径指向一个文件，返回 True；否则返回 False
    """
    # 检查路径是否包含至少一个'/'和一个'.'
    if path.count('/') < 1 or path.count('.') < 1:
        return False

    # 找到最后一个'/'的位置
    last_slash_index = path.rfind('/')

    # 找到最后一个'.'的位置
    last_dot_index = path.rfind('.')

    # 检查最后一个'.'是否在最后一个'/'之后
    if last_slash_index == -1 or last_dot_index <= last_slash_index:
        return False

    # 如果最后一个'.'在字符串末尾，那么它不是一个文件
    if last_dot_index == len(path) - 1:
        return False

    # 检查路径的最后一部分是否以'.'开头
    if path[last_slash_index + 1].startswith('.'):
        return False

    return True


def receive_file(save_path, server_socket, file_name, total_size):
    file_path = os.path.join(save_path, file_name)
    # 检查文件夹是否存在
    if not os.path.exists(save_path):
        # 如果文件夹不存在，则创建文件夹
        os.makedirs(save_path)
        print(f"文件夹 {save_path} 已创建。")
    else:
        print(f"文件夹 {save_path} 已存在。")

    if is_path_a_file(file_path):
        with open(file_path, 'wb') as file:
            received_size = 0
            while True:
                data = server_socket.recv(data_size)
                if not data:
                    break
                file.write(data)
                received_size += len(data)
                percent = (received_size / total_size) * 100 if total_size > 0 else 0
                print(f"\rReceiving {file_name}: {percent:.2f}%", end='')
            print()  # 新行
    else:
        print(f"路径 {file_path} 不是一个文件。")
        if not os.path.exists(file_path):
            os.makedirs(file_path)
            print(f"文件夹 {file_path} 已创建。")
        else:
            print(f"路径 {file_path} 已存在。")


def reSend(client_socket, respose, data):
    """
    重发数据
    :param respose: 响应
    :param data: 数据
    :return: 文件和文件夹列表
    """
    # 等待0.1秒
    time.sleep(0.1)
    print("连接失败，断开连接")
    client_socket.close()  # 关闭连接
    return None
    # # 重试3次
    # for i in range(4):
    #     try:
    #         # 尝试解析数据
    #         files_and_folders = eval(data)
    #         # 返回文件和文件夹列表
    #         return files_and_folders
    #     except Exception as e:
    #         # 如果解析失败，重新发送请求
    #         client_socket.sendall(respose.encode('gbk'))  # 使用GBK编码发送客户端消息
    #         # 等待0.2秒
    #         time.sleep(0.2)
    #         # 打印重试次数
    #         print("重试{}次".format(i + 1))


def start_client(host, port, save_path, data_size):
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect((host, port))

    while True:
        print(
            "Enter the number of the file or folder you want to access, or '../' to go up a directory, or 'ls' to list files and folders:")
        response = input()
        print("获取用户输入成功")
        if response == 'wq':
            client_socket.close()
            print("关闭连接")
            break
        client_socket.sendall(response.encode('gbk'))  # 使用GBK编码发送客户端消息
        data = None
        print("发送数据成功")
        try:
            data = client_socket.recv(data_size).decode('gbk')  # 使用GBK编码接收服务器消息
            print("收到服务器数据")
            if data.startswith("Invalid input"):
                continue
            files_and_folders = eval(data)  # 解析文件和文件夹信息
            print("解析文件和文件夹信息成功")
        except Exception as e:
            print(e)
            files_and_folders = reSend(client_socket, response, data)
            # continue

        if files_and_folders:  # 有文件或文件夹信息
            print("Files and folders:")
            for i, (name, size) in enumerate(files_and_folders):  # 打印文件和文件夹信息
                print(f"{i}: {name} ({size:.2f} MB)")
            if response.isdigit():  # 选择了一个文件或文件夹
                try:
                    index = int(response)
                    file_name, file_size_mb = files_and_folders[index]
                    file_size = int(file_size_mb * 1024 * 1024)
                    receive_file(save_path, client_socket, file_name, file_size)
                except IndexError:
                    print("Invalid selection.")
        elif response == "ls" and (not files_and_folders):
            print("No files or folders to display.")
            client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            client_socket.connect((host, port))

        else:
            print("No files or folders to display.")
            client_socket.close()


if __name__ == "__main__":
    data_size = 1024 * 1024
    start_client('cn-sz-yd-plustmp2.natfrp.cloud', 10620, './', data_size)
